#include "platform/opengl/opengl_buffer.hpp"
#include "xen/core.hpp"

namespace Xen {

/********************
 * VertexBuffer
 *******************/

OpenGLVertexBuffer::OpenGLVertexBuffer(const void* vertex_data, uint32_t size) {
    GLCall(glGenBuffers(1, &vertex_buffer_));
    GLCall(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_));
    GLCall(glBufferData(GL_ARRAY_BUFFER, size, vertex_data, GL_STATIC_DRAW));
}

OpenGLVertexBuffer::OpenGLVertexBuffer(uint32_t size) {
    GLCall(glGenBuffers(1, &vertex_buffer_));
    GLCall(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_));
    GLCall(glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW));
}

OpenGLVertexBuffer::~OpenGLVertexBuffer() {
    GLCall(glDeleteBuffers(1, &vertex_buffer_));
}

void OpenGLVertexBuffer::Bind() const {
    GLCall(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_));
}

void OpenGLVertexBuffer::SetLayout(const BufferLayout &layout) {
    layout_ = layout;
}

const BufferLayout &OpenGLVertexBuffer::GetLayout() const {
    return layout_;
}

void OpenGLVertexBuffer::Unbind() const {
    GLCall(glBindBuffer(GL_ARRAY_BUFFER, 0));
}

void OpenGLVertexBuffer::SetData(uint32_t offset, uint32_t size, const void *data) {
    Bind();
    GLCall(glBufferSubData(GL_ARRAY_BUFFER, offset, size, data));
    Unbind();
}

/********************
 * IndexBuffer
 *******************/

OpenGLIndexBuffer::OpenGLIndexBuffer(const uint32_t *indices, uint32_t count): count_(count) {
    GLCall(glGenBuffers(1, &indices_buffer_));
    GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer_));
    GLCall(glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint32_t), indices, GL_STATIC_DRAW));
}

OpenGLIndexBuffer::~OpenGLIndexBuffer() {
    GLCall(glDeleteBuffers(1, &indices_buffer_));
}

void OpenGLIndexBuffer::Bind() const {
    GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer_));
}

void OpenGLIndexBuffer::Unbind() const {
    GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}

}
